home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume19 / rkive / part03 < prev    next >
Encoding:
Internet Message Format  |  1989-06-29  |  43.1 KB

  1. Subject:  v19i100:  Usenet sources archiver, Part03/04
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Kent Landfield <ssbell!kent>
  7. Posting-number: Volume 19, Issue 100
  8. Archive-name: rkive/part03
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 3 (of 4)."
  17. # Contents:  header.c rkive.cf setup.c
  18. # Wrapped by kent@ssbell on Thu Jun  1 16:19:13 1989
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'header.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'header.c'\"
  22. else
  23. echo shar: Extracting \"'header.c'\" \(15302 characters\)
  24. sed "s/^X//" >'header.c' <<'END_OF_FILE'
  25. X/*
  26. X**
  27. X** This software is Copyright (c) 1989 by Kent Landfield.
  28. X**
  29. X** Permission is hereby granted to copy, distribute or otherwise 
  30. X** use any part of this package as long as you do not try to make 
  31. X** money from it or pretend that you wrote it.  This copyright 
  32. X** notice must be maintained in any copy made.
  33. X**
  34. X**  History:
  35. X**    Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
  36. X**                                                               
  37. X*/
  38. X#ifndef lint
  39. Xstatic char SID[] = "@(#)header.c    1.1 6/1/89";
  40. X#endif
  41. X
  42. X#include <stdio.h>
  43. X#include <ctype.h>
  44. X#include <sys/types.h>
  45. X#include "article.h"
  46. X
  47. Xint its(s1)
  48. Xregister char *s1;
  49. X{
  50. X    if (strncmp(s,s1,strlen(s1)) == 0)
  51. X        return(TRUE);
  52. X    return(FALSE);
  53. X}
  54. X
  55. Xint line_type()
  56. X{
  57. X    if (its("Path: "))
  58. X        return PATH;
  59. X    if (its("From: "))
  60. X        return FROM;
  61. X    if (its("Newsgroups: "))
  62. X        return NEWSGROUP;
  63. X    if (its("Subject: "))
  64. X        return SUBJECT;
  65. X    if (its("Keywords: "))
  66. X        return KEYWORDS;
  67. X    if (its("Date: "))
  68. X        return DATE;
  69. X    if (its("Message-ID: "))
  70. X        return MSG_ID;
  71. X    if (its("Lines: "))
  72. X        return NUMLINES;
  73. X    if (its("Approved: "))
  74. X        return APPROVED;
  75. X
  76. X    /* The following is the auxilliary headers used by */
  77. X    /* the moderators of the sources groups. In some  */
  78. X    /* cases, line checks are done with "historical"  */
  79. X    /* auxilliary headers. Most of the moderators have */
  80. X    /* now standardized on comp.sources.unix's format.*/
  81. X
  82. X    /* Archive header lines for comp.sources.unix     */
  83. X    /* for comp.sources.amiga, comp.sources.atari.st, */
  84. X    /* comp.sources.misc, and comp.sources.x.         */
  85. X
  86. X    if (its("Submitted-by: "))         
  87. X        return SUBMITTED_BY;
  88. X    if (its("Posting-number: "))       
  89. X        return POSTING_NUMBER;
  90. X    if (its("Archive-name: "))
  91. X        return ARCH_NAME;
  92. X
  93. X    /* Archive header lines for historical purposes */
  94. X    /* once used in comp.sources.misc               */
  95. X
  96. X    if (its("Submitted-By: "))        
  97. X        return SUBMITTED_BY;
  98. X    if (its("comp.sources.misc: "))
  99. X        return POSTING_NUMBER;
  100. X    if (its("Archive-Name: "))
  101. X        return ARCH_NAME;
  102. X
  103. X    /* Archive header lines used in comp.sources.games   */
  104. X    /* Archive-name is the same as comp.sources.unix     */
  105. X
  106. X    if (its("Submitted by: "))        
  107. X        return SUBMITTED_BY;
  108. X    if (its("Comp.sources.games: "))
  109. X        return POSTING_NUMBER;
  110. X
  111. X    /* Auxiliary header used as a backward reference   */
  112. X    /* to the location of the initially posted sources */
  113. X    /* in the event of a patch. This line only exists  */
  114. X    /* if the current article is a patch.              */
  115. X
  116. X    if (its("Patch-To: "))
  117. X        return PATCH_TO;
  118. X
  119. X    /* Archive header lines for historical purposes */
  120. X    /* once used in mod.sources articles.           */
  121. X
  122. X    if (its("Mod.sources: "))       
  123. X        return POSTING_NUMBER;
  124. X
  125. X    /* The remainder are other types of lines included */
  126. X    /* headers and are includes for formatting output  */
  127. X    /* and for potential future use.                   */
  128. X
  129. X    if (its("References: "))
  130. X        return REFERENCES;
  131. X    if (its("Organization: "))
  132. X        return ORGANIZATION;
  133. X    if (its("Distribution: "))
  134. X        return DISTRIBUTION;
  135. X    if (its("Xref: "))
  136. X        return XREF;
  137. X    if (its("Expires: "))
  138. X        return EXPIRE;
  139. X    if (its("Article-I.D.: "))
  140. X        return ARTICLEID;
  141. X    if (its("Reply-To: "))
  142. X        return REPLY_TO;
  143. X    if (its("Control: "))
  144. X        return CONTROL;
  145. X    if (its("Sender: "))
  146. X        return SENDER;
  147. X    if (its("Followup-To: "))
  148. X        return FOLLOWUP_TO;
  149. X    if (its("Summary: "))
  150. X        return SUMMARY;
  151. X    if (its("Supersedes: "))
  152. X        return SUPERSEDES;
  153. X
  154. X    return OTHER;
  155. X}
  156. X
  157. Xdata(hpfield, size, fldname)
  158. Xchar    *hpfield;
  159. Xint    size;
  160. Xchar    *fldname;
  161. X{
  162. X    register char *ptr;
  163. X    register char *p;
  164. X    char *strncpy();
  165. X    char *strchr();
  166. X
  167. X    for (ptr = strchr(s, ':'); isspace(*++ptr); )
  168. X        ;
  169. X    if (*ptr != '\0') {
  170. X        (void) strncpy(hpfield, ptr, size - 1);
  171. X        /*
  172. X         * Strip trailing newlines, blanks, and tabs from hpfield.
  173. X         */
  174. X        for (p = hpfield; *p; ++p)
  175. X             ;
  176. X        while (--p >= hpfield && (*p == '\n' || *p == ' ' || *p == '\t'))
  177. X             ;
  178. X        *++p = '\0';
  179. X    }
  180. X    if (debug)
  181. X       (void) fprintf(logfp,"%s: %s\n",fldname, hpfield);
  182. X}
  183. X
  184. Xdump_article()
  185. X{
  186. X    char *type_str;
  187. X
  188. X    switch(article.rectype) {
  189. X             case PATCH  : type_str = "PATCH";
  190. X                           break;
  191. X      case INFORMATIONAL : type_str = "INFORMATIONAL"; 
  192. X                           break;
  193. X                 default : type_str = "NORMAL"; 
  194. X                           break;
  195. X    }
  196. X
  197. X    (void) fprintf(logfp,"Article:           [%s]\n",article.newsarticle);
  198. X    (void) fprintf(logfp,"   newsgroup:      [%s]\n",article.newsgroup);
  199. X    (void) fprintf(logfp,"   filename:       [%s]\n",article.filename);
  200. X    (void) fprintf(logfp,"   volume:         [%d]\n",article.volume);
  201. X    (void) fprintf(logfp,"   issue:          [%d]\n",article.issue);
  202. X    (void) fprintf(logfp,"   record type:    [%s]\n", type_str);
  203. X    if (article.rectype == PATCH) {
  204. X        (void) fprintf(logfp,"   patch volume:   [%d]\n",article.patch_volume);
  205. X        (void) fprintf(logfp,"   patch issue:    [%d]\n",article.patch_issue);
  206. X    }
  207. X    (void) fprintf(logfp,"   reposted:       [%s]\n", 
  208. X                   article.repost ? "YES": "NO");
  209. X    (void) fprintf(logfp,"   description:    [%s]\n",article.description);
  210. X    (void) fprintf(logfp,"   author's name:  [%s]\n",article.author_name);
  211. X    (void) fprintf(logfp,"   author's logon: [%s]\n\n",article.author_signon);
  212. X}
  213. X
  214. Xinit_article()
  215. X{
  216. X    article.newsgroup[0] = '\0';
  217. X    article.newsarticle[0] = '\0';
  218. X    article.filename[0] = '\0';
  219. X    article.volume = -1;
  220. X    article.issue = -1;
  221. X    article.rectype = NORMAL;
  222. X    article.repost = FALSE;
  223. X    article.patch_volume = -1;
  224. X    article.patch_issue = -1;
  225. X    article.description[0] = '\0';
  226. X    article.author_name[0] = '\0';
  227. X    article.author_signon[0] = '\0';
  228. X
  229. X    header.from[0] = '\0';         /* From:                 */
  230. X    header.path[0] = '\0';         /* Path:                 */
  231. X    header.nbuf[0] = '\0';         /* Newsgroups:           */
  232. X    header.subject[0] = '\0';      /* Subject:              */
  233. X    header.ident[0] = '\0';        /* Message-ID:           */
  234. X    header.replyto[0] = '\0';      /* Reply-To:             */
  235. X    header.references[0] = '\0';   /* References:           */
  236. X    header.subdate[0] = '\0';      /* Date: (submission)    */
  237. X    header.subtime = 0;            /* subdate in secs       */
  238. X    header.expdate[0] = '\0';      /* Expires:              */
  239. X    header.ctlmsg[0] = '\0';       /* Control:              */
  240. X    header.sender[0] = '\0';       /* Sender:               */
  241. X    header.followup_to[0] = '\0';  /* Followup-to:          */
  242. X    header.distribution[0] = '\0'; /* Distribution:         */
  243. X    header.organization[0] = '\0'; /* Organization:         */
  244. X    header.numlines[0] = '\0';     /* Lines:                */
  245. X    header.intnumlines = 0;        /* Integer Version       */
  246. X    header.keywords[0] = '\0';     /* Keywords:             */
  247. X    header.summary[0] = '\0';      /* Summary:              */
  248. X    header.approved[0] = '\0';     /* Approved:             */
  249. X    header.xref[0] = '\0';         /* Xref:                 */
  250. X    header.supersedes[0] = '\0';   /* Supersedes:           */
  251. X    header.submitted_by[0] = '\0'; /* Submitted_by:         */
  252. X    header.posting_num[0] = '\0';  /* Posting-number:       */
  253. X    header.archive_name[0] = '\0'; /* Archive-name:         */
  254. X    header.patch_to[0] = '\0';     /* Patch-To:             */
  255. X}
  256. X
  257. Xstore_line()
  258. X{
  259. X    char *strchr(), *strcpy(), *strstrip(), *substr();
  260. X    char *dp, *sp;
  261. X    char wrk[20];
  262. X
  263. X    switch(line_type()) {
  264. X
  265. X    case PATH: /*PATH REQUIRED************************/
  266. X        data(header.path, sizeof(header.path), "PATH:");
  267. X        break;
  268. X
  269. X    case FROM: /*FROM REQUIRED************************/
  270. X        data(header.from, sizeof(header.from), "FROM:");
  271. X        break;
  272. X
  273. X    case NEWSGROUP: /*NEWSGROUP REQUIRED**************/
  274. X        data(header.nbuf, sizeof(header.nbuf), "NEWSGROUPS:");
  275. X        if ((sp = strchr(s,':')) != NULL) {
  276. X             do {
  277. X                 ++sp;
  278. X             } while(!isalpha(*sp));
  279. X             /* remove all crossposting labels */
  280. X             if ((dp = strchr(sp,',')) != NULL)
  281. X                 *dp = '\0';
  282. X             (void) strcpy(article.newsgroup,sp);
  283. X        }
  284. X        break;
  285. X
  286. X    case SUBJECT: /*SUBJECT REQUIRED******************/
  287. X        data(header.subject, sizeof(header.subject), "SUBJECT:");
  288. X        /* 
  289. X        ** Save the subject as the description for articles
  290. X        ** that have no volume/issue format. Later in the
  291. X        ** code, this subject line minus the volume/issue
  292. X        ** is stored back in the .description element if
  293. X        ** the volume/issue indicator is found.
  294. X        */
  295. X        (void) strcpy(article.description, header.subject);
  296. X
  297. X        /*
  298. X        ** Check to see if this article is a repost of
  299. X        ** a previously posted article.
  300. X        */
  301. X        if (substr(s, "REPOST") != NULL)
  302. X            article.repost = TRUE;
  303. X
  304. X        /*
  305. X        ** Time to get the filename. Assure that it is in a 
  306. X        ** volume/issue (v01INF1 or v01i001) format.
  307. X        */
  308. X        if ((sp = strchr(s,'v')) == NULL) 
  309. X            return;          /* no volume indicator */
  310. X
  311. X        /* 
  312. X        ** Is there a number that follows 
  313. X        ** the volume indicator ? 
  314. X        */
  315. X        if (*(sp+1) < '0' || *(sp+1) > '9')
  316. X            return;   /* The volume number is missing */
  317. X
  318. X        /*
  319. X        ** Is there a second ':' as well ?
  320. X        */
  321. X        (void) strcpy(article.filename,sp);
  322. X        if ((dp = strchr(article.filename,':')) == NULL) 
  323. X            return;   /* not in v01i001: format */
  324. X
  325. X        /*
  326. X        ** terminate the article's filename and 
  327. X        ** store the article's description 
  328. X        */
  329. X        *dp = '\0';
  330. X        (void) strcpy(article.description, strstrip(++dp));
  331. X
  332. X        /*
  333. X        ** Store the filename in a work 
  334. X        ** buffer so I can stomp on it. 
  335. X        */
  336. X        (void) strcpy(wrk, article.filename);
  337. X
  338. X        /* 
  339. X        ** This is an informational posting.
  340. X        */
  341. X        if ((dp = substr(wrk, "INF")) != NULL) {
  342. X            article.rectype = INFORMATIONAL;
  343. X            article.issue = atoi((dp+3));
  344. X            ++sp;
  345. X            *dp = '\0';
  346. X            article.volume = atoi(sp);
  347. X        }
  348. X
  349. X        /*
  350. X        **  check to see if there is an issue indicator 
  351. X        */
  352. X        else if ((dp = strchr(++sp,'i')) == NULL) 
  353. X            return;   /* proven guilty. not volume/issue format */
  354. X
  355. X        /* parse the volume from the filename */
  356. X        *dp = '\0';
  357. X        article.volume = atoi(sp);
  358. X      
  359. X        /* parse the issue from the filename */
  360. X        sp = ++dp;
  361. X        while (isdigit(*dp)) ++dp;
  362. X        *dp = '\0';
  363. X        article.issue = atoi(sp);
  364. X
  365. X        break;
  366. X
  367. X    case DATE:
  368. X        data(header.subdate, sizeof(header.subdate), "DATE:");
  369. X        break;
  370. X
  371. X    case EXPIRE:
  372. X        data(header.expdate, sizeof(header.expdate), "EXPIRES:");
  373. X        break;
  374. X
  375. X    case MSG_ID:
  376. X        data(header.ident, sizeof(header.ident), "MESSAGE-ID:");
  377. X        break;
  378. X
  379. X    case REPLY_TO:
  380. X        data(header.replyto, sizeof(header.replyto), "REPLY-TO:");
  381. X        break;
  382. X
  383. X    case REFERENCES:
  384. X        data(header.references, sizeof(header.references), "REFERENCES:");
  385. X        break;
  386. X
  387. X    case SENDER:
  388. X        data(header.sender, sizeof(header.sender), "SENDER:");
  389. X        break;
  390. X
  391. X    case FOLLOWUP_TO:
  392. X        data(header.followup_to, sizeof(header.followup_to),"FOLLOWUP-TO:");
  393. X        break;
  394. X
  395. X    case CONTROL:
  396. X        data(header.ctlmsg, sizeof(header.ctlmsg),"CONTROL:");
  397. X        break;
  398. X
  399. X    case DISTRIBUTION:
  400. X        data(header.distribution, sizeof(header.distribution),"DISTRIBUTION:");
  401. X        break;
  402. X
  403. X    case ORGANIZATION:
  404. X        data(header.organization, sizeof(header.organization),"ORGANIZATION:");
  405. X        break;
  406. X
  407. X    case NUMLINES:
  408. X        data(header.numlines, sizeof(header.numlines),"LINES:");
  409. X        header.intnumlines = atoi(header.numlines);
  410. X        break;
  411. X
  412. X    case KEYWORDS:
  413. X        data(header.keywords, sizeof(header.keywords), "KEYWORDS:");
  414. X        break;
  415. X
  416. X    case APPROVED:
  417. X        data(header.approved, sizeof(header.approved), "APPROVED:");
  418. X        break;
  419. X
  420. X    case SUPERSEDES:
  421. X        data(header.supersedes, sizeof(header.supersedes),"SUPERSEDES:");
  422. X        break;
  423. X
  424. X    case XREF:
  425. X        data(header.xref, sizeof(header.xref),"XREF:");
  426. X        break;
  427. X
  428. X    case SUMMARY:
  429. X        data(header.summary, sizeof(header.summary),"SUMMARY:");
  430. X        break;
  431. X
  432. X    case POSTING_NUMBER:
  433. X        data(header.posting_num, sizeof(header.posting_num), "POSTING_NUMBER:");
  434. X        break;
  435. X
  436. X    case SUBMITTED_BY:
  437. X        data(header.submitted_by, sizeof(header.submitted_by), "SUBMITTED_BY:");
  438. X        /* 
  439. X        ** Save the author's name and sign on if specified 
  440. X        ** Can be in any of the following formats:
  441. X    **    kent@ssbell.uucp 
  442. X    **    kent@ssbell.uucp (Kent Landfield)
  443. X    **    Kent Landfield <kent@ssbell.uucp>
  444. X        */
  445. X        if ((sp = strchr(s,':')) != NULL) {
  446. X            (void) strcpy(article.author_signon,(sp+2));
  447. X            /*
  448. X            ** Has a name been attached to the signon ?
  449. X            */
  450. X            if ((dp = strchr(article.author_signon,'<')) != NULL) {
  451. X                *(dp-1) = '\0';
  452. X                (void) strcpy(article.author_name, article.author_signon);
  453. X                (void) strcpy(article.author_signon, ++dp);
  454. X                /*
  455. X                ** Save the name, removing the <>.
  456. X                */
  457. X                if ((dp = strchr(article.author_signon,'>')) != NULL)
  458. X                    *dp = '\0';
  459. X            }
  460. X            else if ((dp = strchr(article.author_signon,'(')) != NULL) {
  461. X                *(dp-1) = '\0';
  462. X                /*
  463. X                ** Save the name, removing the ().
  464. X                */
  465. X                (void) strcpy(article.author_name, ++dp);
  466. X                if ((dp = strchr(article.author_name,')')) != NULL)
  467. X                    *dp = '\0';
  468. X            }
  469. X        }
  470. X        break;
  471. X
  472. X    case ARCH_NAME:
  473. X        data(header.archive_name,sizeof(header.archive_name),"ARCH_NAME:");
  474. X        break;
  475. X
  476. X    case PATCH_TO:
  477. X        data(header.patch_to,sizeof(header.patch_to),"PATCH_TO:");
  478. X        article.rectype = PATCH;        /* set the article type */
  479. X
  480. X        /*
  481. X    ** Parse the initially posted article's volume and issue.
  482. X        ** The format of the auxiliary header is
  483. X        ** 
  484. X        ** Patch-To: Volume 5, Issue 110
  485. X        **
  486. X        ** In the case of multipart initial postings, the Patch-To:
  487. X        ** line points to the first issue.
  488. X        */
  489. X
  490. X        /* 
  491. X        ** First get the volume number.
  492. X        */
  493. X
  494. X        dp = s;
  495. X        while (*dp && (!isdigit(*dp)))
  496. X              ++dp;
  497. X        sp = dp;
  498. X        while (*dp && (isdigit(*dp)))
  499. X              ++dp;
  500. X        *dp = '\0';
  501. X        article.patch_volume = atoi(sp);
  502. X
  503. X        /* 
  504. X        ** Now get the issue number. 
  505. X        */
  506. X
  507. X        ++dp;
  508. X        while (*dp && (!isdigit(*dp)))
  509. X              ++dp;
  510. X        sp = dp;
  511. X        while (*dp && (isdigit(*dp)))
  512. X              ++dp;
  513. X        *dp = '\0';
  514. X        article.patch_issue = atoi(sp);
  515. X        break;
  516. X    }
  517. X    return;
  518. X}
  519. END_OF_FILE
  520. if test 15302 -ne `wc -c <'header.c'`; then
  521.     echo shar: \"'header.c'\" unpacked with wrong size!
  522. fi
  523. # end of 'header.c'
  524. fi
  525. if test -f 'rkive.cf' -a "${1}" != "-c" ; then 
  526.   echo shar: Will not clobber existing file \"'rkive.cf'\"
  527. else
  528. echo shar: Extracting \"'rkive.cf'\" \(9112 characters\)
  529. sed "s/^X//" >'rkive.cf' <<'END_OF_FILE'
  530. X#
  531. X#
  532. X#    @(#)rkive.cf    1.1 6/1/89 
  533. X#
  534. X#    An rkive.cf template.
  535. X#    Copy and edit this to reflect the local archive conditions.
  536. X#    After editing, run ckconfig to display how rkive will interpret
  537. X#    the local specifications.
  538. X#
  539. X#    The format of the configuration file is as follows:
  540. X#
  541. X######################################################################
  542. X#
  543. X#    Global variables
  544. X#        SPOOLDIR - the base directory for the news subsystem
  545. X#        PROBLEMS - The name of the base directory used to store any
  546. X#                          duplicate or "problem" articles. All articles are
  547. X#                          stored under this directory in a newsgroup/volume
  548. X#                          directory.
  549. X#            TYPE    -  This is the archive type (or the archive key)
  550. X#                   There are 3 possible keys:
  551. X#                    Volume-Issue, Archive-Name or Article-Number
  552. X#                   These are used to determine if you wish the 
  553. X#                          articles archived in a 
  554. X#                    /basedir/amiga/Volume1/v001i22 or
  555. X#                    /basedir/amiga/Volume1/sitonit or
  556. X#                    /basedir/amiga/Volume1/44 format
  557. X#         PATCHES     - This variable determines the way in which patches
  558. X#                          are installed into the archive. If the PATCHES
  559. X#                          entry is not defined either globally or within
  560. X#                          the newsgroup, the article is handled as a regular
  561. X#                          article and is stored according to the specified
  562. X#                          parameters of the newsgroup. The following are
  563. X#                          the valid possible values for the PATCHES variable:
  564. X#                             PATCHES=Historical 
  565. X#                                 This is the same as if no PATCHES entry
  566. X#                                 existed at all. It is useful if Historical
  567. X#                                 patches archiving is the default but there
  568. X#                                 are certain newsgroups that have it specified
  569. X#                                 differently.
  570. X#                             PATCHES=Package 
  571. X#                                 Package patches archiving allows the inbound
  572. X#                                 patch to be placed with the directory with
  573. X#                                 the initially posted articles. In this manner
  574. X#                                 all parts and fixes of a package are together
  575. X#                                 making it easier for software retrieval by
  576. X#                                 uucp requests and mail request facilities
  577. X#                                 such as netlib.
  578. X#        MAIL     - If specified, all actions are mailed to the
  579. X#               list of users specified. The user names are
  580. X#               a comma separated list. It is not necessary to
  581. X#                          specify any users. 
  582. X#            OWNER -    The unix login name for the owner of the 
  583. X#                          archive files after they are stored in the archive.
  584. X#            GROUP -    The unix group value for the group ownership of 
  585. X#                          the archive files after they are stored in the 
  586. X#                          archive.
  587. X#            MODE     - The modes of the files residing in the archive.
  588. X#        LOG     - The location of the master log in which all 
  589. X#               actions are logged. 
  590. X#             LOG_FORMAT - The format of the records of the master log file.
  591. X#                          See the man page for article for a discussion of
  592. X#                          the available selection format capabilities.
  593. X#               INDEX    - The location of the master index (if one is kept).
  594. X#                          The index can be used to interface with the netlib 
  595. X#                          source retrieval software facility.
  596. X#           INDEX_FORMAT - The format of the records of the master log file.
  597. X#                          See the man page for article for a discussion of
  598. X#                          the available selection format capabilities.
  599. X#               COMPRESS - The location of the compression utility if the 
  600. X#                          files are to be reduced.
  601. X#
  602. X######################################################################
  603. XSPOOLDIR=/usr/spool/news      
  604. XPROBLEMS=/usenet/problems
  605. XTYPE= Volume-Issue
  606. XPATCHES=Historical
  607. XMAIL=kent
  608. XOWNER=src
  609. XGROUP=archive
  610. XMODE=0444
  611. XLOG=/usenet/archive.log
  612. XLOG_FORMAT= "%B %T" 
  613. XINDEX= /usenet/index
  614. XINDEX_FORMAT= "%B %a %T" 
  615. X#COMPRESS=/usr/lbin/compress
  616. X
  617. X######################################################################
  618. X#
  619. X#    Each Newsgroup to be archived has an entry with the following
  620. X#    possible variables. (Note that all variables are not necessary)
  621. X#    
  622. X#    BASEDIR - This is the path to the base directory of the archive
  623. X#    TYPE    - This is the archive type (or the archive key)
  624. X#          There are 3 possible keys:
  625. X#            Volume-Issue, Archive-Name or Article-Number
  626. X#          These are used to determine if you wish the articles
  627. X#          archived in a 
  628. X#            /basedir/amiga/Volume1/v001i22 or
  629. X#            /basedir/amiga/Volume1/sitonit or
  630. X#            /basedir/amiga/Volume1/44 format
  631. X#    PATCHES - This variable determines the way in which patches
  632. X#                 are installed into the archive. If the PATCHES
  633. X#                 entry is not defined either globally or within
  634. X#                 the newsgroup, the article is handled as a regular
  635. X#                 article and is stored according to the specified
  636. X#                 parameters of the newsgroup. The following are
  637. X#                 the valid possible values for the PATCHES variable:
  638. X#                 PATCHES=Historical 
  639. X#                        This is the same as if no PATCHES entry
  640. X#                        existed at all. It is useful if Historical
  641. X#                        patches archiving is the default but there
  642. X#                        are certain newsgroups that have it specified
  643. X#                        differently.
  644. X#                 PATCHES=Package 
  645. X#                        Package patches archiving allows the inbound
  646. X#                        patch to be placed with the directory with
  647. X#                        the initially posted articles. In this manner
  648. X#                        all parts and fixes of a package are together
  649. X#                        making it easier for software retrieval by
  650. X#                        ftp, uucp requests and mail request facilities
  651. X#                        such as netlib.
  652. X#       MAIL - If specified, all actions are mailed to the
  653. X#          list of users specified. The user names are
  654. X#          a comma separated list.
  655. X#         OWNER - The unix login name for the owner of the archive files 
  656. X#          after they are stored in the archive.
  657. X#      GROUP - The unix group value for the group ownership of the archive 
  658. X#          files after they are stored in the archive.
  659. X#       MODE - The modes of the files residing in the archive.
  660. X#        LOG - The location of the log in which all actions are logged. 
  661. X#    LOG_FORMAT - The format of the records of the master log file.
  662. X#                 See the man page for article for a discussion of
  663. X#                 the available selection format capabilities.
  664. X#      INDEX    - The location of the master index (if one is kept).
  665. X#                 The index can be used to interface with the netlib 
  666. X#                 source retrieval software facility.
  667. X#  INDEX_FORMAT - The format of the records of the master log file.
  668. X#                 See the man page for article for a discussion of
  669. X#                 the available selection format capabilities.
  670. X#      COMPRESS - The location of the compression utility if the files 
  671. X#          are to be reduced.
  672. X#        
  673. X######################################################################
  674. X$$comp.sources.amiga        
  675. X    BASEDIR: /usenet/amiga 
  676. X    TYPE: Volume-Issue
  677. X    MAIL: rick
  678. X    LOG: /usenet/amiga/log
  679. X        INDEX: /usenet/amiga/index
  680. X        INDEX_FORMAT: "%B %a %T" 
  681. X
  682. X$$comp.sources.atari.st
  683. X    BASEDIR: /usenet/atari/st
  684. X    TYPE: Volume-Issue
  685. X    LOG: /usenet/atari/st/log
  686. X        INDEX: /usenet/atari/st/index
  687. X        INDEX_FORMAT: "%B %a %T" 
  688. X
  689. X$$comp.sources.games        
  690. X    BASEDIR: /usenet/games
  691. X    MAIL: rick
  692. X    TYPE: Volume-Issue
  693. X    LOG: /usenet/games/log
  694. X        INDEX: /usenet/games/index
  695. X        INDEX_FORMAT: "%B %a %T" 
  696. X
  697. X$$comp.sources.mac        
  698. X    BASEDIR: /usenet/mac
  699. X    TYPE: Article-Number
  700. X    LOG: /usenet/mac/log
  701. X        INDEX: /usenet/mac/index
  702. X        INDEX_FORMAT: "%O %a %T" 
  703. X
  704. X$$comp.sources.misc        
  705. X    BASEDIR: /usenet/misc
  706. X    TYPE: Volume-Issue
  707. X    MAIL: rick
  708. X    LOG: /usenet/misc/log
  709. X        INDEX: /usenet/misc/index
  710. X        INDEX_FORMAT: "%B %a %T" 
  711. X
  712. X$$comp.sources.unix        
  713. X    BASEDIR: /usenet/unix
  714. X    TYPE: Volume-Issue
  715. X    MAIL: rick
  716. X    LOG: /usenet/unix/log
  717. X        LOG_FORMAT: "%B %a %T" 
  718. X        INDEX: /usenet/unix/index
  719. X        INDEX_FORMAT: "%B %a %T" 
  720. X
  721. X$$comp.sources.x        
  722. X    BASEDIR: /usenet/x
  723. X    TYPE: Archive-Name
  724. X    PATCHES: Package
  725. X    MAIL: rick,kent,mark
  726. X    LOG: /usenet/x/log
  727. X        LOG_FORMAT: "%B %a %T" 
  728. X        INDEX: /usenet/unix/index
  729. X        INDEX_FORMAT: "%B %a %T" 
  730. X
  731. X$$alt.sources
  732. X    BASEDIR: /usenet/alt/sources
  733. X    TYPE: Article-Number
  734. X    LOG: /usenet/alt/sources/log
  735. X        LOG_FORMAT: "%O %S" 
  736. X
  737. X$$alt.sources.amiga
  738. X    BASEDIR: /usenet/alt/sources/amiga
  739. X    TYPE: Article-Number
  740. X    MAIL: rick
  741. X    LOG: /usenet/alt/sources/amiga/log
  742. X        LOG_FORMAT: "%O %S" 
  743. END_OF_FILE
  744. if test 9112 -ne `wc -c <'rkive.cf'`; then
  745.     echo shar: \"'rkive.cf'\" unpacked with wrong size!
  746. fi
  747. # end of 'rkive.cf'
  748. fi
  749. if test -f 'setup.c' -a "${1}" != "-c" ; then 
  750.   echo shar: Will not clobber existing file \"'setup.c'\"
  751. else
  752. echo shar: Extracting \"'setup.c'\" \(16190 characters\)
  753. sed "s/^X//" >'setup.c' <<'END_OF_FILE'
  754. X/*
  755. X**
  756. X** This software is Copyright (c) 1989 by Kent Landfield.
  757. X**
  758. X** Permission is hereby granted to copy, distribute or otherwise 
  759. X** use any part of this package as long as you do not try to make 
  760. X** money from it or pretend that you wrote it.  This copyright 
  761. X** notice must be maintained in any copy made.
  762. X**
  763. X**
  764. X**  History:
  765. X**    Creation: Tue Feb 21 08:52:35 CST 1989 due to necessity.
  766. X**                                                               
  767. X*/
  768. X#ifndef lint
  769. Xstatic char SID[] = "@(#)setup.c    1.1 6/1/89";
  770. X#endif
  771. X
  772. X#include <sys/types.h>
  773. X#include <sys/stat.h>
  774. X#include <stdio.h>
  775. X#include <ctype.h>
  776. X#include <pwd.h>
  777. X#include <grp.h>
  778. X#include <dirent.h>
  779. X#include "cfg.h"
  780. X
  781. X#define GAG(b) ((void) fprintf(errfp,"%s invalid variable, ignoring.\n",b))
  782. X
  783. Xchar spooldir[MAXNAMLEN]     = { SPOOLDIR };
  784. Xchar problems_dir[MAXNAMLEN] = { PROBLEMS_DIR };
  785. X
  786. Xint default_owner = OWNER;
  787. Xint default_group = GROUP;
  788. Xint default_modes = MODES;
  789. Xint default_type = ARTICLE_NUMBER;
  790. Xint default_patch_type = HISTORICAL;
  791. X
  792. X/*
  793. X** compress -
  794. X** Used to  determine whether or not articles should be compressed 
  795. X** to save space. The command to execute is stored in compress.
  796. X*/
  797. Xchar compress[MAXNAMLEN] = { '\0' };
  798. X
  799. X/*
  800. X** mail -
  801. X** If specified, all actions logged are mailed to the list of users 
  802. X** specified.  The user names are a comma seperated list. 
  803. X*/
  804. Xchar mail[MAXNAMLEN] = { '\0' };
  805. X
  806. X/*
  807. X** log -
  808. X** The location of the master log in which all actions are logged. 
  809. X** If not specified, all logged events are printed on stdout.
  810. X*/
  811. Xchar log[MAXNAMLEN] = { '\0' };
  812. X
  813. X/*
  814. X** log_format -
  815. X** The format of each individual log file record. The format is
  816. X** then filled with information contained in the headers.
  817. X*/
  818. Xchar log_format[BUFSIZ] = { '\0' };
  819. X
  820. X/*
  821. X** index -
  822. X** The location of the master index.
  823. X*/
  824. Xchar index[MAXNAMLEN] = { '\0' };
  825. X
  826. X/*
  827. X** index_format -
  828. X** The format of each individual master index record. The format 
  829. X** is then filled with information contained in the headers.
  830. X*/
  831. Xchar index_format[BUFSIZ] = { '\0' };
  832. X
  833. Xchar *config_file;
  834. XFILE *config;
  835. X
  836. Xstruct stat stbuf;
  837. Xstruct passwd *pwent;
  838. X
  839. Xchar *strstrip();
  840. Xchar *strchr();
  841. Xchar *strcpy();
  842. Xvoid exit();
  843. Xstruct passwd *getpwnam();
  844. X
  845. Xstruct restricted_dirs {
  846. X    char   *dirstr;            /* path of restricted directory */
  847. X};
  848. X
  849. Xstatic struct restricted_dirs base_dirs[] = {
  850. X{  "/"               },
  851. X{  "/etc"            },
  852. X{  "/dev"            },
  853. X{  "/dev/dsk"        },
  854. X{  "/dev/rdsk"       },
  855. X{  "/lib"            },
  856. X{  "/stand"          },
  857. X{  "/usr/adm"        },
  858. X{  "/usr/spool/uucp" },
  859. X{  NULL              },
  860. X};
  861. X
  862. Xsetup_defaults()
  863. X{
  864. X    char *sp;
  865. X    char *buf;
  866. X    char buffer[BUFSIZ];
  867. X    char mode_str[128];
  868. X
  869. X    char *sav_format();
  870. X    char *get_compress();
  871. X    char *get_users();
  872. X    FILE *efopen();
  873. X
  874. X    config = efopen(config_file,"r");
  875. X
  876. X    num = -1; /* initialize group structure index */
  877. X    
  878. X    while (fgets(buffer, sizeof buffer, config) != NULL) {
  879. X        /* ignore comments and blank lines */
  880. X        if (*buffer == '#' || *buffer == '\n') 
  881. X            continue;
  882. X
  883. X        buf = buffer;
  884. X
  885. X        /* strip leading spaces and tabs */
  886. X    while(*buf == ' ' || *buf == '\t')
  887. X             ++buf;
  888. X
  889. X        *(buf+(strlen(buf)-1))  = '\0'; /* remove newline */
  890. X
  891. X        /* if embedded comments, truncate at the comment */
  892. X        if ((sp = strchr(buf,'#')) != NULL)
  893. X             *sp = '\0';
  894. X    
  895. X        /* check to see if newsgroup entry */
  896. X
  897. X        if (*buf == '$' && *(buf+1) == '$') {
  898. X            if (++num >= NUM_NEWSGROUPS)
  899. X               error("Maximum number of newsgroups exceeded!!\n", 
  900. X                    "Please increase the NUM_NEWSGROUPS define...");
  901. X
  902. X            sp = buf+2;
  903. X            while (*sp && !isspace(*sp))
  904. X        ++sp;
  905. X            *sp = '\0';
  906. X
  907. X            group[num].owner     = default_owner;
  908. X            group[num].group     = default_group;
  909. X            group[num].modes     = default_modes;
  910. X            group[num].type      = default_type;
  911. X            group[num].patch_type = default_patch_type;
  912. X            (void) strcpy (group[num].ng_name, strstrip(buf+2));
  913. X            group[num].location[0]  = '\0';
  914. X            group[num].mail_list[0] = '\0';
  915. X            group[num].logfile[0]   = '\0';
  916. X            group[num].index[0]     = '\0';
  917. X            group[num].logformat[0] = '\0';
  918. X            group[num].indformat[0] = '\0';
  919. X            group[num].compress[0]  = '\0';
  920. X        }
  921. X
  922. X        else if ((sp = strchr(buf,'=')) != NULL) {
  923. X            sp++;
  924. X                    /* Global assignment */
  925. X            while (*sp == ' ' || *sp == '\t')
  926. X                sp++;
  927. X
  928. X            if (!*sp)        /* is something still there ? */
  929. X        continue;
  930. X
  931. X            switch(*buf) {
  932. X               case 'C': (void) strcpy(compress, get_compress(buf, sp));
  933. X                         break;
  934. X               case 'G': default_group = get_group(buf, sp);
  935. X                         break;
  936. X               case 'I': if (strncmp(buf, "INDEX_FORMAT", 12) == 0)
  937. X                            (void) strcpy(index_format, sav_format(sp));
  938. X                         else if (strncmp(buf, "INDEX", 3) == 0)
  939. X                            (void) strcpy(index, strstrip(sp));
  940. X                         else
  941. X                            GAG(buf);
  942. X                         break;
  943. X               case 'L': if (strncmp(buf, "LOG_FORMAT", 10) == 0)
  944. X                            (void) strcpy(log_format, sav_format(sp));
  945. X                         else if (strncmp(buf, "LOG", 3) == 0)
  946. X                            (void) strcpy(log, strstrip(sp));
  947. X                         else
  948. X                            GAG(buf);
  949. X                         break;
  950. X               case 'M': if (strncmp(buf, "MAIL",4) == 0) 
  951. X                             (void) strcpy(mail,get_users(sp));
  952. X                         else if (strncmp(buf, "MODE",4) == 0) 
  953. X                             default_modes = correct_modes(sp, mode_str);
  954. X                         else
  955. X                             error(buf, "invalid global assignment");
  956. X                         break;
  957. X               case 'O': default_owner = get_owner(buf, sp);
  958. X                         break;
  959. X               case 'P': if (strncmp(buf, "PROBLEMS", 8) == 0)
  960. X                           (void) strcpy(problems_dir, strstrip(sp));
  961. X                         else 
  962. X                           default_patch_type = get_patch_type("Global",buf,sp);
  963. X                         break;
  964. X               case 'S': get_spooldir(buf, sp);
  965. X                         break;
  966. X               case 'T': default_type = get_archive_type("Global", buf, sp);
  967. X                         break;
  968. X               default : error("invalid global assignment:", buf);
  969. X            }
  970. X        }
  971. X        else if ((sp = strchr(buf,':')) != NULL) {
  972. X            sp++;
  973. X                /* group variable assignment */
  974. X            while (*sp == ' ' || *sp == '\t')
  975. X                sp++;
  976. X
  977. X            if (!*sp)        /* is something still there ? */
  978. X        continue;
  979. X
  980. X            switch(*buf) {
  981. X               case 'B': if (strncmp(buf, "BASEDIR",7) == 0) 
  982. X                            get_archive_basedir(sp);
  983. X                         break;
  984. X               case 'C': (void)strcpy(group[num].compress,get_compress(buf,sp));
  985. X                         break;
  986. X               case 'G': group[num].group = get_group(buf, sp);
  987. X                         break;
  988. X               case 'I': if (strncmp(buf, "INDEX_FORMAT", 12) == 0)
  989. X                            (void) strcpy(group[num].indformat,sav_format(sp));
  990. X                         else if (strncmp(buf, "INDEX", 3) == 0)
  991. X                             (void) strcpy(group[num].index, strstrip(sp));
  992. X                         else
  993. X                             GAG(buf);
  994. X                         break;
  995. X               case 'L': if (strncmp(buf, "LOG_FORMAT", 10) == 0)
  996. X                            (void) strcpy(group[num].logformat, sav_format(sp));
  997. X                         else if (strncmp(buf, "LOG", 3) == 0)
  998. X                            (void) strcpy(group[num].logfile, strstrip(sp));
  999. X                         else
  1000. X                            GAG(buf);
  1001. X                         break;
  1002. X               case 'M': if (strncmp(buf, "MAIL",4) == 0)
  1003. X                            (void) strcpy(group[num].mail_list, get_users(sp));
  1004. X                         else if (strncmp(buf, "MODE",4) == 0) 
  1005. X                             group[num].modes = correct_modes(sp, mode_str);
  1006. X                         else 
  1007. X                             GAG(buf);
  1008. X                         break;
  1009. X               case 'O': group[num].owner = get_owner(buf, sp);
  1010. X                         break;
  1011. X               case 'P': group[num].patch_type = get_patch_type(group[num].ng_name,buf,sp);
  1012. X                         break;
  1013. X               case 'T': group[num].type = get_archive_type(group[num].ng_name, buf, sp);
  1014. X                         break;
  1015. X               default : error("invalid group assignment:", buf);
  1016. X            }
  1017. X        }
  1018. X        else /* no idea what it is */
  1019. X            error("unknown line type", buf);
  1020. X    }
  1021. X    (void) fclose(config);
  1022. X}
  1023. X
  1024. Xerror(msg1,msg2)
  1025. X   char *msg1;
  1026. X   char *msg2;
  1027. X{
  1028. X    (void) fprintf(errfp,"%s: %s %s\n",progname,msg1, msg2);
  1029. X    exit(1);
  1030. X}
  1031. X
  1032. X/*
  1033. X** valid_base_directory
  1034. X**
  1035. X** Assure the directory specified in the configuration file 
  1036. X** as the base directory for a newsgroup archive is not found 
  1037. X** in the table of restricted base directories. 
  1038. X**
  1039. X** This kind of checking is almost insulting to me as an 
  1040. X** administrator but, enough people asked me to put it in 
  1041. X** so "this duds for you"..
  1042. X*/
  1043. X
  1044. Xint valid_base_directory(argstr)
  1045. X    char *argstr;
  1046. X {
  1047. X    register char *rp;
  1048. X    register char *dp;
  1049. X    char wpath[MAXNAMLEN];
  1050. X    char lastchar;
  1051. X    struct restricted_dirs *pt;
  1052. X
  1053. X    /* 
  1054. X    ** First check to see if the base directory is any
  1055. X    ** character other than a slash. We need to assure
  1056. X    ** that "../../../etc" or ./etc is not allowed.  We
  1057. X    ** need a valid absolute path with which to do relative
  1058. X    ** path addressing. (Have I confused myself yet ?)
  1059. X    */
  1060. X
  1061. X    if (*argstr != '/') 
  1062. X            return(FALSE);
  1063. X
  1064. X    /* 
  1065. X    ** Strip the string of duplicate '/'s.
  1066. X    ** Also check to assure that the path specified
  1067. X    ** does not contain the '..' sequence.
  1068. X    */
  1069. X
  1070. X    dp = argstr;
  1071. X    rp = wpath;
  1072. X    lastchar = ' ';
  1073. X
  1074. X    while (*dp) {
  1075. X       if (*dp != '/' || lastchar != '/') {
  1076. X           lastchar = *dp;
  1077. X           *rp++ = *dp;
  1078. X       }
  1079. X       if (*dp == '.' && lastchar == '.') {
  1080. X           if ((*(dp+1) == '/') || (*(dp+1) == '\0'))
  1081. X               return(FALSE);
  1082. X       }
  1083. X       ++dp;
  1084. X    }
  1085. X    *rp = '\0';
  1086. X
  1087. X    /* 
  1088. X    ** strip the string of trailing '/'s so
  1089. X    ** I can use the simple checking below.
  1090. X    */
  1091. X
  1092. X    dp = wpath+(strlen(wpath)-1);
  1093. X    while(*dp == '/' && dp > wpath)
  1094. X        *dp = '\0';
  1095. X
  1096. X    /* 
  1097. X    ** check if they match 
  1098. X    */
  1099. X
  1100. X    pt = &base_dirs[0];
  1101. X    while ((pt->dirstr) != NULL) {
  1102. X
  1103. X        if (strcmp(wpath, pt->dirstr) == 0) 
  1104. X            return(FALSE);
  1105. X
  1106. X        pt++;
  1107. X    }
  1108. X    return(TRUE);
  1109. X}
  1110. X
  1111. Xget_archive_basedir(s)
  1112. Xchar *s;
  1113. X{
  1114. X    (void) strcpy(group[num].location, strstrip(s));
  1115. X
  1116. X    if (!valid_base_directory(group[num].location))
  1117. X        error(group[num].ng_name," - Invalid archive base directory!");
  1118. X}
  1119. X
  1120. Xint correct_modes(s,mode_string)
  1121. Xchar *s;
  1122. Xchar *mode_string;
  1123. X{
  1124. X    register int c;
  1125. X    register int i;
  1126. X
  1127. X    i = 0;
  1128. X    (void) sscanf(s, "%s", mode_string);
  1129. X    while ((c = *mode_string++) >= '0' && c <= '7')
  1130. X        i = (i << 3) + (c - '0');
  1131. X    mode_string--;
  1132. X    return(i);
  1133. X}
  1134. X
  1135. Xchar *get_compress(buffer,cmd)
  1136. Xchar *buffer;
  1137. Xchar *cmd;
  1138. X{
  1139. X    static char *rp;
  1140. X
  1141. X    if (!valid_variable(buffer, "COMPRESS", 8))
  1142. X        return(NULL);
  1143. X    
  1144. X    rp = strstrip(cmd);
  1145. X
  1146. X    /* need to assure the user has specified */
  1147. X    /* a valid executable path.              */
  1148. X
  1149. X    if (stat(rp, &stbuf) != 0) 
  1150. X        error("Can't find specified COMPRESS -", rp);
  1151. X
  1152. X    return(rp);
  1153. X}
  1154. X        
  1155. X
  1156. Xint get_group(buffer, valstr)
  1157. Xchar *buffer;
  1158. Xchar *valstr;
  1159. X{
  1160. X    char *wp;
  1161. X    struct group *grent;
  1162. X    struct group *getgrnam();
  1163. X
  1164. X    if (!valid_variable(buffer, "GROUP", 5))
  1165. X        return(default_group);
  1166. X    
  1167. X    /* group specified by names but */
  1168. X    /* needs to be numbers          */
  1169. X
  1170. X    wp = strstrip(valstr);
  1171. X
  1172. X    if ((grent = getgrnam(wp)) == NULL)
  1173. X         error("Invalid system group:",wp);
  1174. X    return(grent->gr_gid);
  1175. X}
  1176. X
  1177. X
  1178. Xint get_owner(buffer, valstr)
  1179. Xchar *buffer;
  1180. Xchar *valstr;
  1181. X{
  1182. X    char *wp;
  1183. X
  1184. X    if (!valid_variable(buffer, "OWNER", 5))
  1185. X        return(default_owner);
  1186. X    
  1187. X    /* owner specified by names but */
  1188. X    /* needs to be numbers          */
  1189. X
  1190. X    wp = strstrip(valstr);
  1191. X
  1192. X    if ((pwent = getpwnam(wp)) == NULL)
  1193. X         error("Invalid user:",wp);
  1194. X    return(pwent->pw_uid);
  1195. X}
  1196. X
  1197. Xint get_archive_type(ngname, buffer, s)
  1198. Xchar *ngname;
  1199. Xchar *buffer;
  1200. Xchar *s;
  1201. X{
  1202. X    int return_type;
  1203. X
  1204. X    if (!valid_variable(buffer, "TYPE", 4))
  1205. X        return(default_type);
  1206. X    
  1207. X    if (strcmp(s, "Archive-Name") == 0) 
  1208. X        return_type = ARCHIVE_NAME;
  1209. X    else if (strcmp(s, "Volume-Issue") == 0) 
  1210. X        return_type = VOLUME_ISSUE;
  1211. X    else if (strcmp(s, "Article-Number") == 0) 
  1212. X        return_type = ARTICLE_NUMBER;
  1213. X    else {
  1214. X        (void) fprintf(errfp,"%s: %s: %s %s\n", progname,
  1215. X                   ngname, "Invalid Archive Type:", s);
  1216. X        (void) fprintf(errfp,"\tTYPE Must be %s, %s or %s\n",
  1217. X                   "Archive-Name", "Volume-Issue", "Article-Number");
  1218. X        exit(1);
  1219. X    }
  1220. X
  1221. X    return(return_type);
  1222. X}
  1223. X
  1224. Xint valid_variable(buffer, variable, length)
  1225. Xchar *buffer;
  1226. Xchar *variable;
  1227. Xint length;
  1228. X{
  1229. X    if (strncmp(buffer, variable, length) != 0) {
  1230. X        GAG(buffer);
  1231. X        return(FALSE);
  1232. X    }
  1233. X    return(TRUE);
  1234. X}
  1235. X
  1236. X
  1237. Xget_spooldir(buffer,s)
  1238. Xchar *buffer;
  1239. Xchar *s;
  1240. X{
  1241. X    static char *rp;
  1242. X
  1243. X    if (!valid_variable(buffer, "SPOOLDIR", 8))
  1244. X        (void) strcpy(spooldir, SPOOLDIR);
  1245. X
  1246. X    else {
  1247. X        rp = strstrip(s);
  1248. X
  1249. X        /* need to assure the user has specified */
  1250. X        /* a valid directory path for the base   */
  1251. X        /* directory for the news subsystem..    */
  1252. X    
  1253. X        if (stat(rp, &stbuf) != 0) 
  1254. X            error("Can't find SPOOLDIR -", rp);
  1255. X    
  1256. X        (void) strcpy(spooldir, rp);
  1257. X    }
  1258. X}
  1259. X
  1260. Xchar *get_users(s)
  1261. Xchar *s;
  1262. X{
  1263. X    char *strcat();
  1264. X
  1265. X    static char users[512];
  1266. X    char tmp_users[512];
  1267. X    char *list, *name;
  1268. X    char *cp, *dp;
  1269. X    register int i;
  1270. X
  1271. X    /* prepare the string for saving by stripping any spaces */
  1272. X
  1273. X    for (i = 0; i < sizeof users; i++)
  1274. X       users[i] = '\0';
  1275. X
  1276. X    cp = s;
  1277. X    dp = users;
  1278. X    while (*cp) {
  1279. X          if (*cp != ' ' && *cp != '\t')
  1280. X              *dp++ = *cp;
  1281. X          ++cp;
  1282. X    }
  1283. X      
  1284. X    /* need to check the specified user list */
  1285. X    /* to assure that all users are valid    */
  1286. X
  1287. X    (void) strcpy(tmp_users, users);
  1288. X    *users = NULL;
  1289. X
  1290. X    name = tmp_users;
  1291. X
  1292. X    while (name != NULL) {
  1293. X        /* is there additional users specified ? */
  1294. X    if ((list = strchr(name,',')) != NULL) {
  1295. X             list++;
  1296. X             *(list-1) = '\0';
  1297. X        }
  1298. X
  1299. X        /* check if user is found in passwd file */
  1300. X        if ((pwent = getpwnam(name)) != NULL) {
  1301. X            if (*users != NULL) {
  1302. X                (void) strcat(users, ",");
  1303. X                (void) strcat(users, name);
  1304. X            }
  1305. X            else 
  1306. X                (void) strcpy(users, name);
  1307. X        }
  1308. X        else 
  1309. X            error("Invalid user:",name);
  1310. X        name = list;
  1311. X    }
  1312. X    return(users);
  1313. X}
  1314. X
  1315. X/*
  1316. X** get a specified format from the buffer
  1317. X**    Must allow for spaces and tabs so they
  1318. X**      need to be passed intact in the format.
  1319. X*/
  1320. Xchar *sav_format(s)
  1321. X    char *s;
  1322. X{
  1323. X    static char *cp;
  1324. X    char *dp;
  1325. X    
  1326. X    if ((cp = strchr(s,'"')) != NULL && 
  1327. X        (dp = strchr(++cp,'"')) != NULL) {
  1328. X        *dp = '\0';
  1329. X    }
  1330. X    else
  1331. X        cp = NULL;
  1332. X    return(cp);
  1333. X}
  1334. X
  1335. Xint get_patch_type(ngname,buffer, s)
  1336. Xchar *ngname;
  1337. Xchar *buffer;
  1338. Xchar *s;
  1339. X{
  1340. X    int return_type;
  1341. X
  1342. X    if (!valid_variable(buffer, "PATCHES", 7))
  1343. X        return(default_type);
  1344. X    
  1345. X    if (strcmp(s, "Package") == 0) 
  1346. X        return_type = PACKAGE;
  1347. X    else if (strcmp(s, "Historical") == 0) 
  1348. X        return_type = HISTORICAL;
  1349. X    else {
  1350. X        (void) fprintf(errfp,"%s: %s: %s %s\n", progname,
  1351. X                   ngname, "Invalid Patches Type:", s);
  1352. X        (void) fprintf(errfp,"\tTYPE Must be %s, or %s\n",
  1353. X                   "Historical", "Package");
  1354. X        exit(1);
  1355. X    }
  1356. X    return(return_type);
  1357. X}
  1358. END_OF_FILE
  1359. if test 16190 -ne `wc -c <'setup.c'`; then
  1360.     echo shar: \"'setup.c'\" unpacked with wrong size!
  1361. fi
  1362. # end of 'setup.c'
  1363. fi
  1364. echo shar: End of archive 3 \(of 4\).
  1365. cp /dev/null ark3isdone
  1366. MISSING=""
  1367. for I in 1 2 3 4 ; do
  1368.     if test ! -f ark${I}isdone ; then
  1369.     MISSING="${MISSING} ${I}"
  1370.     fi
  1371. done
  1372. if test "${MISSING}" = "" ; then
  1373.     echo You have unpacked all 4 archives.
  1374.     rm -f ark[1-9]isdone
  1375. else
  1376.     echo You still need to unpack the following archives:
  1377.     echo "        " ${MISSING}
  1378. fi
  1379. ##  End of shell archive.
  1380. exit 0
  1381.  
  1382.